/*
 * Copyright © Jack魏 2022 - 2022, All Rights Reserved.
 */

package com.jack.thread.t02;

import lombok.SneakyThrows;

/**
 * synchronized 使用
 *
 * @author Jack魏
 * @since 2022/11/20 21:16
 */
public class SynchronizedTest {
    /**
     * 买票线程
     */
    static class UserThread extends Thread {
        private static int num = 10;

        public UserThread(String name) {
            super(name);
        }

        @Override
        public void run() {
            // 如果局部变量没有变化，多线程也不会出现问题
            for (int i = 0; i < num;) {
                System.out.println(this.getName() + " 售出了第: " + (num) + "号票");
                // 这里局部变量变化
                num--;
            }
        }
    }

    /**
     * 买票线程-synchronized关键字，错误锁对象
     */
    static class UserThreadSynErr extends Thread {
        private static Integer num = 10;

        public UserThreadSynErr(String name) {
            super(name);
        }

        @Override
        public void run() {
            synchronized (num) {
                for (int i = 0; i < num; i++) {
                    System.out
                        .println(this.getName() + " 售出了第: " + (num) + "号票。锁对象HashCode：" + System.identityHashCode(num));
                    // 需要反编译，查看这句话为：this.num = Integer.valueOf(this.num.intValue() - 1)
                    // Integer.valueOf 就是先去缓存里面找，找不到 new Integer
                    num--;
                }
            }
        }
    }

    /**
     * 买票线程-synchronized关键字
     */
    static class UserThreadSyn extends Thread {
        private static Integer num = 10;

        // 加锁对象，只要不变就行
        private static Object lock = new Object();

        public UserThreadSyn(String name) {
            super(name);
        }

        @Override
        public void run() {
            while (num > 0) {
                synchronized (lock) {
                    if (num > 0) {
                        System.out.println(
                                this.getName() + " 售出了第: " + (num) + "号票。锁对象HashCode：" + System.identityHashCode(lock));
                        // 需要反编译，查看这句话为：this.num = Integer.valueOf(this.num.intValue() - 1)
                        // Integer.valueOf 就是先去缓存里面找，找不到 new Integer
                        num--;
                    }else {
                        System.out.println("卖完了");
                    }
                }
                // 延迟需要放到synchronized外部，不然就会单线程处理了。
                try  {
                    sleep(1000);
                }  catch  (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        // runThread1();
        // runThread2();
        runThread3();
    }

    /**
     * 演示正常加锁
     */
    private static void runThread3() {
        UserThreadSyn userThread1 = new UserThreadSyn("Jack");
        UserThreadSyn userThread2 = new UserThreadSyn("Mark");
        UserThreadSyn userThread3 = new UserThreadSyn("Tony");

        userThread1.start();
        userThread2.start();
        userThread3.start();
    }

    /**
     * 演示错误加锁
     */
    private static void runThread2() {
        UserThreadSynErr userThread1 = new UserThreadSynErr("Jack");
        UserThreadSynErr userThread2 = new UserThreadSynErr("Mark");
        UserThreadSynErr userThread3 = new UserThreadSynErr("Tony");

        userThread1.start();
        userThread2.start();
        userThread3.start();
    }

    /**
     * 演示未加锁
     */
    private static void runThread1() {
        UserThread userThread1 = new UserThread("Jack");
        UserThread userThread2 = new UserThread("Mark");
        UserThread userThread3 = new UserThread("Tony");

        userThread1.start();
        userThread2.start();
        userThread3.start();
    }
}
